package com.musicalevents.authentication;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.musicalevents.dao.UserDAO;
import com.musicalevents.entity.User;

@Service
public class CustomUserDetailsService implements UserDetailsService  {
	
	@Autowired
	private UserDAO userDAO;
	
	/**
	 * Returns a populated {@link UserDetails} object. 
	 * The login is first retrieved from the database and then mapped to 
	 * a {@link UserDetails} object.
	 */
	@Transactional(readOnly = true)
	public UserDetails loadUserByUsername(String login)
			throws UsernameNotFoundException {
		
		CustomUserDetails spring_security_user = null;
		
		User appUser = userDAO.findByLogin(login);
		
		if (appUser != null) {
			boolean enabled = true;
			boolean accountNonExpired = true;
			boolean credentialsNonExpired = true;
			boolean accountNonLocked = true;
			
			spring_security_user = new CustomUserDetails(
												appUser.getId(),
												appUser.getLogin(),
												appUser.getPassword(),
												enabled,
												accountNonExpired,
												credentialsNonExpired,
												accountNonLocked);
			spring_security_user.setAuthorities(getAuthorities(appUser.getRole().getRole()));			
		}
		
		return (spring_security_user);
	}

	/**
	 * Retrieves a collection of {@link GrantedAuthority} based on a numerical role
	 * @param role the numerical role
	 * @return a collection of {@link GrantedAuthority
	 */	
	public Collection<? extends GrantedAuthority> getAuthorities(Integer role) {
		List<GrantedAuthority> authList = getGrantedAuthorities(getRoles(role));
		return authList;
	}

	/**
	 * Converts a numerical role to an equivalent list of roles
	 * @param role the numerical role
	 * @return list of roles as as a list of {@link String}
	 */
	public List<String> getRoles(Integer role) {
		List<String> roles = new ArrayList<String>();

		if (role.intValue() == 1) {
			roles.add("ROLE_USER");

		} else if (role.intValue() == 2) {
			roles.add("ROLE_USER");
			roles.add("ROLE_ADMIN");
		}

		return roles;
	}

	/**
	 * Wraps {@link String} roles to {@link SimpleGrantedAuthority} objects
	 * @param roles {@link String} of roles
	 * @return list of granted authorities
	 */
	public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) {
		List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
		for (String role : roles) {
			authorities.add(new SimpleGrantedAuthority(role));
		}
		return authorities;
	}	
	
}
